package comAPIdlw.address;

import comAPIdlw.tool.Base58;
import comAPIdlw.tool.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

/**
 * @Author: dlw
 * @QQ : 1595507337
 * @Date: 2021/12/23 9:04
 * @desc:该类用于推到生成原生格式的比特币地址，并对比特币地址进行规范校验
 */
public class BitCoinAddress {
    //该方法用于生成密钥对，并返回密钥对信息
     public KeyPair generateKey(){

         try {
             //密钥对生成器                             椭圆曲线EC算法
             KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
              //
             ECGenParameterSpec spec= new ECGenParameterSpec("secp256k1");
             //初始化   initial   init
             generator.initialize(spec);
             //生成密钥对
               return generator.genKeyPair();
         } catch (NoSuchAlgorithmException e) {
             e.printStackTrace();
         } catch (InvalidAlgorithmParameterException e) {
             e.printStackTrace();
         }
         return  null;
     }

     //该方法用于推到得到一个原始格式的地址，并将生成的地址返回
                                //密钥对  生成地址
     public  String newAddress(KeyPair keyPair){
         //得到公钥
        // PublicKey Publickey = keyPair.getPublic();
         //转换ecc
         ECPublicKey publicKey=(ECPublicKey)keyPair.getPublic();
         //对公钥进行hash算法    原始公钥格式65字节   0x00  x坐标  32    y坐标  32
         //一套api多个算法    公钥密码学  rsa  ecc
         //获取xy坐标
       //  ECPoint point = publicKey.getW();
         //转换字节数组
//         byte[] xBytes = point.getAffineX().toByteArray();
//         byte[] yBytes = point.getAffineY().toByteArray();
//         System.out.println(xBytes.length);
//         System.out.println(yBytes.length);
         byte[] pubkey = toUnCompressPubKey(publicKey);
         byte[] sha256 = Hash.SHA256(pubkey);
         byte[] pubhash = Hash.RipeMD160(sha256);
         //对公钥hash前面加上版本号
         byte[] version = new byte[1];
         version[0]=0x00;

         byte[] ver_pubhash = new byte[version.length + pubhash.length];
         System.arraycopy(version,0,ver_pubhash,0,version.length);
         System.arraycopy(pubhash,0,ver_pubhash,version.length,pubhash.length);
         //对公钥hash进行256，取前4个字节
         byte[] hash1 = Hash.SHA256(ver_pubhash);
         byte[] hash2 = Hash.SHA256(hash1);
         byte[] check = new byte[4];
         System.arraycopy(hash2,0,check,0,check.length);

         byte[] var_pubhash_check=new byte[ver_pubhash.length+check.length];
         System.arraycopy(ver_pubhash,0,var_pubhash_check,0,ver_pubhash.length);
         System.arraycopy(check,0,var_pubhash_check,ver_pubhash.length,check.length);

         //对var_pubhash_check进行base58编码
        return Base58.encode(var_pubhash_check);
         //System.out.println(address);
     }


     //该方法用于返回比特币是否符合规范     address 要校验的地址
       public  boolean validateAddress(String address){
         if ("".equals(address)|| address==null){
             return  false;
         }
           //解码
           byte[] ver_pubhash_check = Base58.decode(address);

         if (ver_pubhash_check.length<4){
             return false;
         }
           byte[] check = new byte[4];
           System.arraycopy(ver_pubhash_check,ver_pubhash_check.length-4,check,0,check.length);
           byte[] ver_pubhash= new byte[ver_pubhash_check.length-4];
           System.arraycopy(ver_pubhash_check,0,ver_pubhash,0,ver_pubhash.length);
           //双重256 hash取前四个字节
           byte[] hash1 = Hash.SHA256(ver_pubhash);
           byte[] hash2 = Hash.SHA256(hash1);
           //取前4个字节
               byte[] check_sum=  new byte[4];
           System.arraycopy(hash2,0,check_sum,0,check_sum.length);

          return Arrays.equals(check,check_sum);

       }



   // UnCompress     该类生成未压缩的公钥    publicKey ec算法的公钥    return
     public  byte[] toUnCompressPubKey(ECPublicKey publicKey){
             ECPoint point= publicKey.getW();
         byte[] xBytes = point.getAffineX().toByteArray();
         byte[] yBytes = point.getAffineY().toByteArray();

       //原始65字节   x 坐标    1-32   04+x+y
         byte[] pubKey = new byte[1+2*32];
         pubKey[0]=04;
         if (xBytes.length==32){
             //数组拷贝   x坐标复制到pubKey     复制谁  哪里复制  复制到哪里去   放着位置   复制多少个
             System.arraycopy(xBytes,0,pubKey,1,xBytes.length);
         }else if (xBytes.length>32){
             System.arraycopy(xBytes,1,pubKey,1,32);
         }
         //y  33-65
         if (yBytes.length==33) {
             //数组拷贝   x坐标复制到pubKey     复制谁  哪里复制  复制到哪里去   放着位置   复制多少个
             System.arraycopy(yBytes, 0, pubKey, 33, yBytes.length);
         }else if (yBytes.length>32){
             System.arraycopy(yBytes,1,pubKey,33,32);
         }


         return pubKey;
     }


//    public static void main(String[] args) {
//        BitCoinAddress test = new BitCoinAddress();
//        KeyPair keyPair = test.generateKey();
//       // System.out.println(keyPair);
//        String str = test.newAddress(keyPair);
//        System.out.println(str);
//        boolean b = test.validateAddress(str);
//        System.out.println(b);
//
//
//
//    }
    }

